﻿using System;
using Cms.Data.ORM;
using Cms.Utilities;
using NHibernate;

namespace Cms.Data
{
    public class BaseRepository
    {
        private readonly ISession _session;
        
        public BaseRepository()
        {
            _session = SessionManager.Current;
        }
        
        //This alternative constructor is used by the test project
        public BaseRepository(ISession testSession)
        {
            _session = testSession;
        }
        
        protected ISession Session
        {
            get { return _session; }
        }

        protected void SaveEntity(object obj, string methodName)
        {
            ITransaction tx = null;
            try
            {
                tx = BeginTransactionAndSave(obj);
            }
            catch (Exception ex)
            {
                RollbackTransaction(methodName, tx, ex);
                throw;
            }
        }
        
        protected void DeleteEntity(object obj, string methodName)
        {
            ITransaction tx = null;
            try
            {
                tx = Session.BeginTransaction();
                Session.Delete(obj);
                Session.Flush();
                tx.Commit();
                EvictCache();
            }
            catch (Exception ex)
            {
                RollbackTransaction(methodName, tx, ex);
                throw;
            }
        }
        
        protected void DeleteHql(string hql, string methodName)
        {
            ITransaction tx = null;
            try
            {
                tx = Session.BeginTransaction();
                Session.Delete(hql);
                Session.Flush();
                tx.Commit();
                EvictCache();
            }
            catch (Exception ex)
            {
                RollbackTransaction(methodName, tx, ex);
                throw;
            }
        }

        protected ITransaction BeginTransactionAndSave(object obj)
        {
            ITransaction tx = Session.BeginTransaction();
            Session.SaveOrUpdate(obj);
            Session.Flush();
            tx.Commit();
            EvictCache();
            return tx;
        }
        
        protected void RollbackTransaction(string methodName, ITransaction tx, Exception ex)
        {
            if (tx != null)
            {
                try
                {
                    tx.Rollback();
                }
                catch (HibernateException he)
                {
                    Logging.LogError(methodName + ", Rollback failed", he);
                }
            }
            Logging.LogError(methodName, ex);
        }

        protected void EvictCache()
        {
            Session.SessionFactory.EvictQueries();
            foreach (var collectionMetadata in Session.SessionFactory.GetAllCollectionMetadata())
                Session.SessionFactory.EvictCollection(collectionMetadata.Key);
            foreach (var classMetadata in Session.SessionFactory.GetAllClassMetadata())
                Session.SessionFactory.EvictEntity(classMetadata.Key);
        }
    }
}